<?php
require_once(DB_FILE);

require_once(GAME_CONFIG_FILE);
require_once(GAME_LOGIC_FILE);
require_once(USER_CONTROLLER_FILE);
require_once(UTILS_FILE);

class GameController {

	private $dmg_done = 0;
	
	private $f_fft = false;
	private $f_plc = false;
	private $f_drw = false;
	private $f_atk = false;
	private $f_err = false;
	private $f_win = false;
	
        private function updateTime($game_id) {
            
            $last_time=time();
            
            $query = "UPDATE games
                SET last_time=$last_time
                WHERE id=$game_id";
					
					
	    $db = new DBConnection();
            $db->executeQuery($query);
        }
        
        
	//public access
	public function play($command, $uid) {
	
		$this->f_fft = false;
		$this->f_plc = false;
		$this->f_drw = false;
		$this->f_atk = false;
		$this->f_err = false;
		$this->f_win = false;
	
		$game_id = $this->_query_game_id( $uid );
		$record = $this->_query_record($game_id);
		$gameLogic = $this->_parse_record_to_game_logic($record);
		
		//ceck for op. forfiet
		if($record['forfiet'] != 0) {
                        $this->updateTime($game_id);
			$this->_remove_game_record($game_id);
			$this->_create_after_game_session($record, $uid);
                        if($record['forfiet'] == $uid) {
                            $this->updateLoose($uid, $record);
                            return FORFIET_STATE . $this->_unchanged_state($uid, $record);
                        }
                        else {
                            $this->updateWin($uid, $record);
                            return END_GAME_MSG . $this->_unchanged_state($uid, $record);
                        }
		}
                
                //speciel case for pushing forfiet
		if($command == COM_FORFIET) {
                        $this->updateTime($game_id);
			$winer = $this->_set_to_loose($uid, $game_id, $record);
                        $this->_add_old_game($record, $winer);
			$this->_create_after_game_session($record, $uid);
			if($uid == $record['turn']) {
				$this->_switch_turn($uid, $game_id, $record['p1_id'], $record['p2_id']);
			}
			$this->_update_last_action($game_id, $command);
                        $this->updateLoose($uid, $record);
			return FORFIET_STATE . $this->_unchanged_state($uid, $record);
		}
		
		if($uid != $record['turn']) {	//not your turn, how did you get here?
			return CURRENT_STATE . $this->_unchanged_state($uid, $record);
		}
		
		$new_gl = $this->_parse_move($gameLogic, $command, $uid);		//make the actual move

		if($this->f_err) {
			return RETURN_ERROR . $this->_unchanged_state($uid, $record);
		}

		if($this->f_win) {	//must be after atk case
                        $this->updateTime($game_id);
			$winer = $this->_set_to_win($uid, $game_id, $record);
                        $this->_add_old_game($record, $winer);
			$this->_create_after_game_session($record, $uid);
			$this->_switch_turn($uid, $game_id, $record['p1_id'], $record['p2_id']);
			$this->_update_last_action($game_id, $command);
                        $this->updateWin($uid, $record);
                        return END_GAME_MSG . $this->_return_state_to_user($uid, $record, $new_gl, $command);
		}
		
	/********************************************************
	*		at this point action is okay, and has been
	*		made. switch turns, update db to new_gl
	********************************************************/

		$this->_update_db($uid, $new_gl, $game_id, $record, $command);
		return CURRENT_STATE . $this->_return_state_to_user($uid, $record, $new_gl, $command);
	}
	public function state($uid) {
		
		$game_id = $this->_query_game_id( $uid );
		$record = $this->_query_record($game_id);
		$gameLogic = $this->_parse_record_to_game_logic($record);
		
		//op. forfiet
		if($record['forfiet'] != 0) {
                        $this->updateTime($game_id);
			$this->_remove_game_record($game_id);
			$this->_create_after_game_session($record, $uid);
                        $this->updateWin($uid, $record);
			return FORFIET_STATE . $this->_unchanged_state($uid, $record);
		}
		if($record['game_ended'] != 0) {
                        $this->updateTime($game_id);
			$this->_set_to_loose($uid, $game_id, $record);
			$this->_remove_game_record($game_id);
			$this->_create_after_game_session($record, $uid);
                        $this->updateLoose($uid, $record);
			return END_GAME_MSG . $this->_return_state_to_user($uid, $record, $gameLogic->return_answer(), $record['last_action']);
		}
		
		return CURRENT_STATE . $this->_return_state_to_user($uid, $record, $gameLogic->return_answer(), $record['last_action']);
	}
	
	//initalizers
	private function _query_game_id($uid) {
		$query = "SELECT game_id FROM users
					WHERE id = $uid 
					LIMIT 1";

		$db = new DBConnection();
		if ($db->executeQuery($query)) {
			$result = $db->getResult();
			if( ($result != null) && ($result->num_rows > 0) ) {
				$row = $result->fetch_assoc();
			}
		}
		if(isset($row['game_id'])) {
			return $row['game_id'];
		}
		return null;
	}
	private function _query_record($game_id) {
			
		$query = "SELECT * FROM games
					WHERE `id` = $game_id 
					LIMIT 1";

		$db = new DBConnection();
		if ($db->executeQuery($query)) {
			$result = $db->getResult();
			if( ($result != null) && ($result->num_rows > 0) ) {
				$row = $result->fetch_assoc();
			}
		}
		if(isset($row)) {
			return $row;
		}
		return null;
	}
	private function _parse_record_to_game_logic($row) {
		$board1 = $this->_parse_board($row['p1_board']);
		$board2 = $this->_parse_board($row['p2_board']);
		$towers1 = $this->_parse_towers($row['p1_towers']);
		$towers2 = $this->_parse_towers($row['p2_towers']);
		$holding_cards1 = $this->_parse_cards($row['p1_cards']);
		$holding_cards2 = $this->_parse_cards($row['p2_cards']);

		$player_1 = new Player($row['p1_id'], $holding_cards1, $board1, $towers1);
		$player_2 = new Player($row['p2_id'], $holding_cards2, $board2, $towers2);
		
		return new GameLogic($player_1, $player_2);
	}
	
	//last game state to csv string
	private function _unchanged_state($uid, $record) {
		if($uid == $record['p1_id']) {
			$game_state = $record['p1_turn'].','
							.$record['p1_board'].','
							.$this->_reverse_board($record['p2_board']).','
							.$record['p1_towers'].','
							.$record['p2_towers'].','
							.$record['p1_cards'].','
							."null";
		}
		else {
			$game_state = $record['p2_turn'].','
							.$record['p2_board'].','
							.$this->_reverse_board($record['p1_board']).','
							.$record['p2_towers'].','
							.$record['p1_towers'].','
							.$record['p2_cards'].','
							."null";
		}
		return $game_state;
	}
	private function _return_state_to_user($uid, $record, $dtu, $command) {
        if($uid == $record['p1_id']) {
			$game_state = $record['p1_turn'].','
							.$dtu['p1_board'].','
							.$this->_reverse_board($dtu['p2_board']).','
							.$dtu['p1_towers'].','
							.$dtu['p2_towers'].','
							.$dtu['p1_cards'].','
							.$command;
		}
		else {
			$game_state = $record['p2_turn'].','
							.$dtu['p2_board'].','
							.$this->_reverse_board($dtu['p1_board']).','
							.$dtu['p2_towers'].','
							.$dtu['p1_towers'].','
							.$dtu['p2_cards'].','
							.$command;
		}
		return $game_state;
	}
	private function _reverse_board($board) {
		return $board;
                $cards = explode(":",wordwrap($board, CARD_SOLDIER_LEN, ":", True));
		$reverse = 	$cards[2].$cards[1].$cards[0].
					$cards[5].$cards[4].$cards[3].
					$cards[8].$cards[7].$cards[6].
					$cards[11].$cards[10].$cards[9];
		return $reverse;
                
                /*$reverse = "";
                for($i=0; $i<ROW_SIZE; $i++) {
                    for($j=COL_SIZE-1; $j>=0; $j++) {
                        $reverse .= $cards[$i * ROW_SIZE + $j];
                    }
                }
                return $reverse;*/
	}

        //used in pos_game.phph
        public static function setLastGameId($id) {
            $_SESSION["last_game_id"] = $id;
        }
        //used in pos_game.phph
        public static function getLastGameId() {
            if(isset($_SESSION["last_game_id"])) {
                return $_SESSION["last_game_id"];
            }
            return null;
        }
        
	private function _create_after_game_session($record,$uid) {
	
		//clear currenet game stats

                self::setLastGameId($record['id']);

	}
        
        //db updates
	private function _add_old_game($record, $winer) {
	
		$game_id = $record['id'];
		$duration = time() - $record['start_time'];
		$won = $winer;
		if($won == $record['p1_id']) {
			$lost = $record['p2_id'];
                        $won_dmg = $record['p1_dmg'];
			$loose_dmg = $record['p2_dmg'];
		}
		else {
			$lost = $record['p1_id'];
			$won_dmg = $record['p2_dmg'];
			$loose_dmg = $record['p1_dmg'];
		}
		
		$moves = $record['move_counter'];

		$query = 	"INSERT INTO old_games (game_id,duration,won,lost,moves,won_dmg,loose_dmg)
					VALUES ($game_id,$duration,$won,$lost,$moves,$won_dmg,$loose_dmg)";
		
		$db = new DBConnection();
		$db->executeQuery($query);
	}
	private function _remove_game_record($game_id) {
		$query = "DELETE FROM games
					WHERE id=$game_id";
					
	    $db = new DBConnection();
		$db->executeQuery($query);

		$query = "UPDATE users
					SET game_id=0
					WHERE game_id=$game_id";
					
					
	    $db = new DBConnection();
		$db->executeQuery($query);
	}
	private function _set_to_loose($uid, $game_id, $record) {
            if($record['p1_id'] == $uid) {
                    $winner = $record['p2_id'];
            }
            else {
                    $winner = $record['p1_id'];
            }
            $query = "UPDATE games 
                    SET game_ended=$winner, forfiet=$uid
                    WHERE id=$game_id";

            $db = new DBConnection();
            $db->executeQuery($query);
            return $winner;
	}
	private function _set_to_win($uid, $game_id, $record) {
            $query = "UPDATE games 
                    SET game_ended=$uid
                    WHERE id=$game_id";

            $db = new DBConnection();
            $db->executeQuery($query);
            
         
            
            return $uid;
	}
        private function updateLoose($uid, $record) {
            $query = "SELECT loose FROM users 
                    WHERE id=$uid";
            
            $db = new DBConnection();
            if ($db->executeQuery($query)) {
                $result = $db->getResult();
                if( ($result != null) && ($result->num_rows > 0) ) {
                        $row = $result->fetch_assoc();
                }
                else {
                    Utils::Error("ERROR IN DB");
                }
            }
            else {
                Utils::Error("ERROR IN DB");
            }
            
            $loose = $row['loose'] + 1;
            
            $query = "UPDATE users 
                    SET loose=$loose
                    WHERE id=$uid";

            $db = new DBConnection();
            $db->executeQuery($query); 
        }
        private function updateWin($uid, $record) {
            // get user points and loosses
            if($record['p1_id'] == $uid) {
                $add_points = $record['p2_dmg'];
            }
            else {
                $add_points = $record['p1_dmg'];
            }
            
            $query = "SELECT points, win FROM users 
                    WHERE id=$uid";
            
            $db = new DBConnection();
            if ($db->executeQuery($query)) {
                $result = $db->getResult();
                if( ($result != null) && ($result->num_rows > 0) ) {
                        $row = $result->fetch_assoc();
                }
                else {
                    Utils::Error("ERROR IN DB");
                }
            }
            else {
                Utils::Error("ERROR IN DB");
            }
            
            $points = $row['points'] + $add_points;
            $win = $row['win'] + 1;
            
            $query = "UPDATE users 
                    SET win=$win, points=$points
                    WHERE id=$uid";

            $db = new DBConnection();
            $db->executeQuery($query);   
        }
	private function _switch_turn($uid, $game_id, $p1, $p2) {
		if($uid == $p1) {
			$next_turn = $p2;
		}
		else {
			$next_turn = $p1;
		}
		
		$query = "UPDATE games 
					SET turn=$next_turn
					WHERE id=$game_id";

		$db = new DBConnection();
		$db->executeQuery($query);
	}
	private function _update_last_action($game_id, $command) {
		$query = "UPDATE games 
					SET last_action='$command'
					WHERE id=$game_id";
					
		$db = new DBConnection();
		$db->executeQuery($query);
	}
	private function _update_db($uid, $output, $game_id, $record, $command) {
		$next_turn = "";
		
		if($uid == $record['p1_id']) {
			$next_turn = $record['p2_id'];
			$p1_turn = 0;
			$p2_turn = 1;
			
			$p1_dmg = $record['p1_dmg'] + $this->dmg_done;
			$p2_dmg = $record['p2_dmg'] + 0;
		}
		else {
			$next_turn = $record['p1_id'];
			$p1_turn = 1;
			$p2_turn = 0;
			
			$p1_dmg = $record['p1_dmg'] + 0;
			$p2_dmg = $record['p2_dmg'] + $this->dmg_done;
		}

		$p1_board=$output['p1_board'];
		$p2_board=$output['p2_board'];
		$p1_towers=$output['p1_towers'];
		$p2_towers=$output['p2_towers'];
		$p1_cards=$output['p1_cards'];
		$p2_cards=$output['p2_cards'];
		$move_counter=$record['move_counter']+1;
		$last_time=time(); 
		
		$query = "UPDATE games 
					SET p1_board='$p1_board', p2_board='$p2_board',
					p1_towers='$p1_towers', p2_towers='$p2_towers',
					p1_cards='$p1_cards', p2_cards='$p2_cards',
					turn=$next_turn, move_counter=$move_counter,
					p1_turn=$p1_turn, p2_turn=$p2_turn,
					last_time=$last_time, last_action='$command',
					p1_dmg=$p1_dmg, p2_dmg=$p2_dmg
					WHERE id=$game_id";

	    $db = new DBConnection();
		$db->executeQuery($query);
	}

	
	//parsring
	private function _parse_cards($str) {
		$cards = array();
		$cards_data = explode(":",wordwrap($str, ID_SEG_LEN, ":", True));
		for($i = 0; $i < MAX_CARD_HOLDING; $i++) {
			if($cards_data[$i] != "xxx") {
				$cards[] = $cards_data[$i] + 0;
			}
		}
		return $cards;
	}
	private function _parse_towers($str) {
		$towers = array();
		$towers_data = explode(":",wordwrap($str, TOWER_SEG_LEN, ":", True));
		for($i = 0; $i < ROW_SIZE; $i++) {
			$towers[] = $towers_data[$i] + 0;
		}
		return $towers;
	}
	private function _parse_board($str) {
		$tmp = array();
		$cols = explode(":",wordwrap($str, COL_SIZE*CARD_SOLDIER_LEN, ":", True));
		foreach($cols as $rows) {
			$tmp[] = explode(":",wordwrap($rows, CARD_SOLDIER_LEN, ":", True));
		}
		$board = null;
		for($i = 0; $i < ROW_SIZE; $i++) {
			for($j = 0; $j < COL_SIZE; $j++) {
				$data = explode(":",wordwrap($tmp[$i][$j], ID_SEG_LEN, ":", True));
				if($data[0] == "xxx" || $data[1] == "xxx" ) {
					$board[$i][$j] = null;
				}
				else {
					$board[$i][$j] = new PlacedCard($data[0] + 0, $data[1] + 0);
				}
			}
		}
		return $board;
	}
	
	
	private function _parse_move($game_logic, $move, $uid) {
	
		$this->dmg_done = 0;
		
		if($move == null) {
			$this->f_err = true;
			return;
		}
		$move_array = explode("|", $move);
		
		if(count($move_array) > 2) {
			$this->f_err = true;
			return;
		}
		
		foreach($move_array as $single_move) {
			$parsed_move = explode(" ", $single_move);
			switch ($parsed_move[0]) {
				case COM_ATTACK:
					if( $this->_chack_attack_command($parsed_move) &&
												($this->f_plc == false) &&
												($this->f_atk == false) ) {
						
						$this->dmg_done = $game_logic->attack_card($uid, $parsed_move[1], $parsed_move[2]);
                                                if($this->dmg_done == null) {
                                                    $this->f_err = true;
                                                    return null;
                                                }
						if($this->dmg_done < 0) {
							$this->f_err = true;
							return null;
						}
						else {
							$this->f_atk = true;
						}
						if($game_logic->has_won($uid)) {
							$this->f_win = true;
						}
					}
					else {
						$this->f_err = true;
					}
					break;
				case COM_PLACE_CARD:
					if($this->_chack_place_card_command($parsed_move) &&
												($this->f_drw == false) &&
												($this->f_plc == false) &&
												($this->f_atk == false)) {
												
						$ret = $game_logic->place_card($uid, $parsed_move[1], $parsed_move[2], $parsed_move[3]);
						if($ret == null) {
							$this->f_err = true;
							return null;
						}
						else {
							$this->f_plc = true;
						}
					}
					else {
						$this->f_err = true;
					}
					break;
				case COM_DRAW_CARD:
					if($this->_chack_draw_card_command($parsed_move) &&
												($this->f_drw == false) &&
												($this->f_plc == false)) {
												
						$ret = $game_logic->draw_card($uid);
						if($ret == null) {
							$this->f_err = true;
							return null;
						}
						else {
							$this->f_drw = true;
						}
					}
					else {
						$this->f_err = true;
					}
					break;
				default:
					$this->f_err = true;
					return null;
					break;
			}
		}
		return $game_logic->return_answer();
	}	
	
	//check moves
	private function _chack_attack_command($parsed_move) {
		if(count($parsed_move) != 3) {
			return false;
		}
		if(is_numeric($parsed_move[1]) == false || is_numeric($parsed_move[2]) == false) {
			return false;
		}
		for($i = 1; $i < 3; $i++) {
			if(count(explode(".",$parsed_move[$i])) > 1 ) {
				return false;
			}
		}
		return true;
	}
	private function _chack_place_card_command($parsed_move) {
		if(count($parsed_move) != 4) {
			return false;
		}
		if(is_numeric($parsed_move[1]) == false || is_numeric($parsed_move[2]) == false || is_numeric($parsed_move[3]) == false) {
			return false;
		}
		for($i = 1; $i < 4; $i++) {
			if(count(explode(".",$parsed_move[$i])) > 1 ) {
				return false;
			}
		}
		return true;
	}
	private function _chack_draw_card_command($parsed_move) {
		if(count($parsed_move) != 1) {
			return false;
		}
		return true;
	}
	private function _chack_forfiet_command($parsed_move) {
		return $this->_chack_draw_card_command($parsed_move);
	}



}
?>



